﻿@page "/"
@using System.Diagnostics
@using System.Diagnostics.CodeAnalysis
@using System.Text.Json
@using System.IO
@using Microsoft.JSInterop
@using zy_simu.Data
@using Microsoft.AspNetCore.Components.Forms
@using System.Threading;

@inject IJSRuntime JSRuntime
@inject DialogService DialogService
@inject SimuCfg emu_cfg
@inject DeviceSnap dev_snap
@inject MacroService macro_service
@inject BlazorWebViewReaction blazor_webview

<BootstrapBlazorRoot>
<div style="margin:20px">

    <div class="row">
        <div class="col-4">
            <DisplayPanelGeneral @ref="DispPanelGen"></DisplayPanelGeneral>
            <Divider Text="模拟测试参数" />
            <HardwarePanel @ref="HWPanel"></HardwarePanel>
            <div class="row" style="margin-top:10px; float:right;">
                <div class="col-auto">
                    <button class="btn btn-primary" @onclick="BtnSimuCtrlSwitch"><i class="fas fa-play"> </i> @btn_power_txt</button>
                </div>
                <div class="col-auto">
                    <button class="btn btn-primary" @onclick="btn_emu_setting" disabled="@(btn_power_txt == "关闭模拟器")"> <i class="fas fa-gear"> </i> 配置模拟器 </button>
                </div>
                <div class="col-auto">
                    <button class="btn btn-primary" @onclick="btn_test1_click"> 测试和自检 </button>
                </div>
                <div class="col-auto">
                    @TestString
                </div>

            </div>
        </div>
        <div class="col-4"> @*参数表和状态表*@
            <div class="row">
                <CtrlParameterTable @ref="param_table"></CtrlParameterTable>
            </div>
            <Divider />
            <div class="row">
                <CtrlStateTable @ref="state_table"></CtrlStateTable>
            </div>
        </div>
        <div class="col-4"> @*参数表, 启动/设置按钮 *@
            @*宏记录和执行器*@
            @* <MacroPanel @ref="macro_ex"></MacroPanel>   
            <Divider />
            <div class="row">
                <div class="col-auto">
                    <InputFile OnChange="HandleM0FileSelected" accept=".hex" />
                </div>
                <div class="col-auto">
                    <button class="btn btn-primary" @onclick="btn_burn_m0"><i class="fas fa-play"> </i> 烧录M0 </button>
                </div>
                <div class="col-auto">
                    <button class="btn btn-primary" @onclick="btn_burn_cat1"><i class="fas fa-play"> </i> 烧录CAT1 </button>
                </div>
            </div> *@
            <div class="row">
                <Textarea PlaceHolder="请输入 ..." rows="23" @bind-Value="@dev_snap.m0_log" readonly IsAutoScroll=true />
            </div>
            <div class="row">
                <Textarea PlaceHolder="请输入 ..." rows="23" @bind-Value="@dev_snap.cat1_log" readonly IsAutoScroll=true />
            </div>

        </div>
    </div>
</div>
</BootstrapBlazorRoot>

@code {
    private double window_height;
    private double window_width;
    private DisplayPanel? DispPanel = default!;
    private DisplayPanelGeneral DispPanelGen = default!;
    // private DisplayPanel326? DispPanel326 = default!;
    // private DisplayPanel1625 DispPanel1625 = default!;
    [AllowNull] private HardwarePanel HWPanel;
    [AllowNull] private CtrlParameterTable param_table;
    [AllowNull] private CtrlStateTable state_table;
    // private DeviceSnap? dev_snap = null;
    private MacroPanel macro_ex = default!;


    protected override void OnInitialized()
    {
        DispPanel = DispPanelGen;
        base.OnInitialized();
    }
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender) // 根据页面大小匹配控件size
        {
            window_height = await JSRuntime.InvokeAsync<double>("JsGetWindowHeight");
            param_table.SetHeight((int)(window_height - 135) / 5 * 2);
            state_table.SetHeight((int)(window_height - 135) / 5 * 3);
            StateHasChanged();
        }
    }

    // sleep util next TASK_PERIOD comming
    private System.DateTime task_start_time = System.DateTime.Now;
    private int test_flag = 0;
    private int[] test_int = new int[50];
    private int test_idx = 0;
    private void WaitNextTaskLoop(ref System.DateTime start)
    {
        int interval = dev_snap.TASK_PERIOD*2 - (int)(System.DateTime.Now - start).TotalMilliseconds;
        test_int[(test_idx++)%50] = interval;
        int sum = 0;
        for(int i = 0; i < 50; i++) sum += test_int[i];
        sum /= 50;
        if (interval > 0)
            System.Threading.Thread.Sleep(interval);
        else
            test_flag++;
        start = System.DateTime.Now;
    }
    private Task main_loop_task = null!;
    private CancellationTokenSource main_loop_cancel = new CancellationTokenSource();
    private int main_loop_state = 0;
    // TASK_PERIOD main loop
    private void main_loop(CancellationToken cancel)
    {
        for (System.DateTime start = System.DateTime.Now; !cancel.IsCancellationRequested; WaitNextTaskLoop(ref start))
        {
            if (main_loop_state == 0)
            {
                Debug.Assert(dev_snap != null);
                // 读取仿真器快照
                dev_snap.Start(emu_cfg);

                // according dev info, init simulator console
                HWPanel.SimuInput(dev_snap);
                dev_snap.Sync(); // firstly pre sync data

                param_table.InitTable(dev_snap.pm_tb);
                main_loop_state++;
                continue;
            }

            // 修改参数表和状态表
            dev_snap.ChangePmTable(param_table.modified_idx, param_table.modified_value);
            dev_snap.ChangeStTable(state_table.modified_idx, state_table.modified_value);
            param_table.modified_idx = state_table.modified_idx = -1;
            // 读取并且设置key变化
            dev_snap.key_val = DispPanel.GetKey();
            // 模拟器仿真硬件变化 - 更新模拟硬件变化
            HWPanel.SimuInput(dev_snap);
            HWPanel.SimuOutput(dev_snap);

            // 宏操作
            // macro_ex.Refresh();
            // sync with simulate device
            dev_snap.Sync();

            // HWPanel.SimuOutput(dev_snap);
            // 掉电, 关机
            if (!emu_cfg.pow && !emu_cfg.battery)
            {
                SimuCtrlPowerOff();
                InvokeAsync(StateHasChanged);
                continue;
            }

            // 启动/关闭cat1
            if (HWPanel.GetCat1Status(dev_snap)) 
                dev_snap.Cat1PowerOn();
            else 
                dev_snap.Cat1PowerOff();

            // 更新显示变化
            DispPanel.Display();
            param_table.UpdateData();    // 更新参数表
            state_table.UpdateData(dev_snap.st_tb);     // 更新状态表
            InvokeAsync(StateHasChanged);
        }
        main_loop_state = 0;
        return;
    }


    // 启动/关闭模拟器
    public async Task<bool> SimuCtrlPowerOn()
    {
        // 安装停止函数, 供blazor外部强制停止时调用。
        blazor_webview.Close = SimuCtrlPowerOff;
        // 判断是否要清除flash，相当于恢复出厂设置
        if (emu_cfg.factory_reset)
        {
            if (File.Exists(@".\app\user_data\zy_m0_eeprom.dat"))
                File.Delete(@".\app\user_data\zy_m0_eeprom.dat");
            if (File.Exists(@".\app\user_data\cat1_local.dat"))
                File.Delete(@".\app\user_data\cat1_local.dat");
            if (File.Exists(@".\app\user_data\http_triplet.dat"))
                File.Delete(@".\app\user_data\http_triplet.dat");
            if (File.Exists(@".\app\user_data\zy_m0_flash.dat"))
                File.Delete(@".\app\user_data\zy_m0_flash.dat");
        }
        // 启动硬件模拟
        HWPanel.Start();
        // await InvokeAsync(StateHasChanged);
        // 重新根据设备型号安装合适的display panel
        DispPanel = DispPanelGen;
        DispPanel.Init();
        // macro_service.DispPanel = DispPanel;
        // start main_loop task
        main_loop_task = Task.Run(() => main_loop(main_loop_cancel.Token), main_loop_cancel.Token);
        return true;
    }
    public async Task SimuCtrlPowerOff()
    {
        DispPanel.CloseDisplay();
        main_loop_cancel.Cancel();
        System.Threading.Thread.Sleep(300); // wait for main_loop task to exit
        KgConsoleManager.Hide();
        dev_snap.Stop();
        blazor_webview!.get_webview().Reload();
        blazor_webview!.Close = null;
    }
    private string btn_power_txt = "启动模拟器";
    public async Task BtnSimuCtrlSwitch()
    {
        if (btn_power_txt == "启动模拟器")
        {
            System.Console.WriteLine("---------- Simulator Running ----------");
            if (await SimuCtrlPowerOn() == false) return;
            macro_service.Init(dev_snap, DispPanel!, HWPanel, emu_cfg);
            btn_power_txt = "关闭模拟器";
        }
        else
        {
            System.Console.WriteLine("---------- Simulator Closing ----------");
            await SimuCtrlPowerOff();
            btn_power_txt = "启动模拟器";
        }
    }

    private async Task HandleM0FileSelected(InputFileChangeEventArgs e)
    {
        HexFileParser hex_file = new();
        await hex_file.Parser(e.File.OpenReadStream(maxAllowedSize: 10_000_000));


        // zy_simu.Data.HexFileParser parser = new zy_simu.Data.HexFileParser("");
        // HexFileParser parser = new HexFileParser("");
        // SelFile = e.File;
        // System.Console.WriteLine($"File name: {SelFile.Name}");
    }

    private async void btn_burn_m0()
    {
        IBrowserFile SelFile = null;
        var option = new DialogOption()
            {
                Title = "M0镜像(hex)选择",
                ShowFooter = false,
                Size = Size.Medium,
            };
        // 传递option给内部模板，这样内部可以call option.CloseDialogAsync() 来主动关闭对话框
        option.Component = BootstrapDynamicComponent.CreateComponent<SelFileDialog>(new Dictionary<string, object?>
            {
                [nameof(SelFileDialog.option)] = option,
                [nameof(SelFileDialog.SelFile)] = SelFile,
            });
        await DialogService.Show(option);
    }
    private void btn_burn_cat1()
    {

    }

    private void btn_emu_setting()
    {
        var option = new DialogOption()
        {
            Title = "仿真器配置",
            ShowFooter = false,
            Size = Size.Medium,
        };
        // 传递option给内部模板，这样内部可以call option.CloseDialogAsync() 来主动关闭对话框
        option.Component = BootstrapDynamicComponent.CreateComponent<SimuCfgModeDialog>(new Dictionary<string, object?>
        {
            [nameof(SimuCfgModeDialog.option)] = option,
        });
        DialogService.Show(option);
    }

    private string TestString = "";
    private void btn_test1_click()
    {
        // TODOOO OTA 
        using (StreamReader reader = new StreamReader("D:\\@prjs\\akm4s\\next_simu\\m0\\build\\obj\\akm3s.bin"))
        {
            // dev_snap.ExchangeWithDev(false);
        }


        //     DialogService.Show(new DialogOption()
        //     {
        //         Title = "BLE 设备选择",
        //         Component = BootstrapDynamicComponent.CreateComponent<BleConfigDialog>(),
        //         Size = Size.Large,
        //     });
        // }
    }
}
